package com.example.demo.websocket;
import jakarta.websocket.Session;
import jakarta.websocket.server.PathParam;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import jakarta.websocket.server.ServerEndpoint;
import jakarta.servlet.http.HttpSession;
import jakarta.websocket.*;
import com.alibaba.fastjson2.*;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ConcurrentHashMap;
/**
 * 消息提醒计数WebSocket
 */
//@ServerEndpoint("/ws?userId={userId}&mySessionId={mySessionId}")
@ServerEndpoint("/ws/{userId}/{mySessionId}")
@Component
@Slf4j
public class TestWebSocketServer {
    /**
     * 与某个客户端的连接会话，需要通过它来给客户端发送数据
     */
    private Session session;
    /**
     * 用户ID
     */
    private Long userId;
    private String mySessionId;
/**
 * concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。
 * 虽然@Component默认是单例模式
 * 的，但springboot还是会为每个websocket连接初始化一个bean，所以可以用一个静态set保存起来。
 *      */
    private static final CopyOnWriteArraySet<TestWebSocketServer> webSockets = new CopyOnWriteArraySet<>();
    /**
     * 用来存在线连接用户信息
     */
    //private static final ConcurrentHashMap<Long, Session> sessionPool = new ConcurrentHashMap<>();

    /**
     * 链接成功调用的方法
     */
    //private static final ConcurrentHashMap<Long, CopyOnWriteArraySet<Session>> onesSessions = new ConcurrentHashMap<>();
    private static final ConcurrentHashMap<String, CopyOnWriteArraySet<Session>> mySessionPool = new ConcurrentHashMap<>();



    @OnOpen
    public void onOpen(Session session, @PathParam(value = "userId") Long userId, @PathParam(value = "mySessionId") String
            mySessionId) {
        this.session = session;
        this.userId = userId;

        this.mySessionId = mySessionId;


        webSockets.add(this);
        //sessionPool.put(userId, session);
        mySessionPool.putIfAbsent(mySessionId, new CopyOnWriteArraySet<Session>());
        CopyOnWriteArraySet<Session> a = mySessionPool.get(mySessionId);
        if(a!=null && a.size()>=2){ log.info("该连接{}可能超过两人了",mySessionId); }
        else {
            mySessionPool.replace(mySessionId, a.add(session) ? a : a);
            log.info("用户{}加入到会话连接{}中", userId, mySessionId);
            log.info("总分页连接数：{}",webSockets.size());
            //log.info("建立与UserID：{}的消息提醒计数连接", userId);
        }
    }

    /**
     * 链接关闭调用的方法
     */
    @OnClose
    public void onClose() throws Throwable {
        webSockets.remove(this);
        //sessionPool.remove(this.userId);
        //log.info("关闭与UserID：{}的消息提醒计数连接", userId);
        CopyOnWriteArraySet<Session> a = mySessionPool.get(mySessionId);
        mySessionPool.replace(mySessionId,a.remove(session)?a:a);
        log.info("用户{}离开了会话连接{}", userId, mySessionId);
        log.info("总分页连接数：{}",webSockets.size());
        if(a.isEmpty()){
            mySessionPool.remove(mySessionId);
            log.info("由于会话连接{}中已无人，连接关闭",mySessionId);
            this.finalize();
        }
    }

    /**
     * 收到客户端消息后调用的方法
     */
    @OnMessage
    public void onMessage(String message) {
        Map<String,Object> map = JSON.parseObject(message,Map.class);
        String data = map.get("content").toString();
        //Object o = JSON.parse(message);
        log.info("接收到UserID：{}的消息：<{}>在会话连接{}中", userId, data,mySessionId);

        sendOneMessage(message);


    }

    /**
     * 发送错误时的处理
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("发送到UserID：{}的消息传输失败", userId, error);
    }

    /**
     * 广播消息
     *
     * @param message
     */
    public void sendAllMessage(String message) {
        for (TestWebSocketServer socketServer : webSockets) {
            if (socketServer.session.isOpen()) {
                socketServer.session.getAsyncRemote().sendText(message);
            }
        }
    }
     /**单人单播消息
     * @param message
     */
    public void sendOneMessage(String message) {
        //Session session = sessionPool.get(userId);
        /*
        if (session != null && session.isOpen()) {
            session.getAsyncRemote().sendText(message);
        }
         */
        //Session session = sessionPool.get(userId);
        CopyOnWriteArraySet<Session> a = mySessionPool.get(mySessionId);
        if(a.size()==1)
            log.info("只有你一人");
        for (Session s : a) {
            if(s!=session){
                if(s.isOpen())
                    s.getAsyncRemote().sendText(message);
                else
                    log.warn("session{}未开启",s);
            }
        }


       /*
        if(session!=null && session.isOpen()){

        }
        */

    }

    /**
     * 多人单播消息
     *
     * @param userIds
     * @param message
     */
    public void sendMoreMessage(Long[] userIds, String message) {
        for (Long userId : userIds) {
            //Session session = sessionPool.get(userId);
            if (session != null && session.isOpen()) {
                session.getAsyncRemote().sendText(message);
            }
        }

    }
}
